/*
 * Copyright 2008 Wink Saville
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.saville.TestSerdes;

import java.io.*;
import junit.framework.Assert;
import android.os.Parcel;
import android.os.Bundle;
import android.app.Activity;

import com.saville.debug.*;
import com.saville.serdes.*;
import com.saville.serdes.StringSer;

/*
 * Test Mc's.
 * 
 * This is an McActivity it extends McActivity, calls super.onCreate(icicle,
 * "name") and implements processMsg.
 * 
 * It also tests various forms of Mcs.
 */
public class TestSerdes extends Activity {

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);

        Log.appName = "TestSerdes abc";

        testSerialization();
    }

    void testSerialization() {

        try {
            String tStrg = "12345678901234567890123456789012";
            byte data[] = new byte[32];

            for (int i = 0; i < data.length; i++) {
                data[i] = (byte) (i & 0xff);
            }

            /* Test String serialization */
            SerdesBinary serdes = new SerdesBinary();
            StringSer ss = new StringSer("hi");
            ss.serialize(serdes);
            byte b[] = serdes.data();
            serdes.init(b, 0, serdes.size());
            String strg = (String) serdes.readObject();
            Assert.assertEquals(strg, "hi");

            /* TODO: Add more tests */

            /* Print lengths */
            int l = tString(tStrg);
            Log.print("<String std> l=%d", l);
            l = tStringParcel(tStrg);
            Log.print("<String Parcel> l=%d", l);
            l = tStringSer(tStrg);
            Log.print("<StringSer> l=%d", l);

            /* Variables for performance measurements */
            int count = 10;
            long durs[] = new long[count];
            int len;

            /*
             * Measure performance of standard serialization for an array of
             * bytes
             * 
             * I've observed the first time is quite slow so as not to overly
             * skew the results to one first.
             */
            long st = Timing.readTsc();
            tArray(data);
            double ds = Timing.tscToSecs(Timing.readTsc() - st);
            Log.print("First ds=%f rate=%f/s time/per=%f", ds, 1.0 / ds, ds);
            st = Timing.readTsc();
            len = tArray(data);
            ds = Timing.tscToSecs(Timing.readTsc() - st);
            Log.print("data len=%d ds=%f rate=%f/s time/per=%f", len, ds, 1.0 / ds, ds);

            st = Timing.readTsc();
            for (int k = 0; k < count; k++) {
                long start = Timing.readTsc();
                tArray(data);
                durs[k] = Timing.readTsc() - start;
            }
            ds = Timing.tscToSecs(Timing.readTsc() - st);
            double rate = count / ds;
            Log.print("AVG <byte std> ds=%f rate=%f/s time/per=%f", ds, rate, 1.0 / rate);
            for (long dur : durs) {
                ds = Timing.tscToSecs(dur);
                Log.print("         ds=%f rate=%f/s time/per=%f", ds, 1.0 / ds, ds);
            }

            /*
             * Measure performance of serializing a String
             */
            System.gc();
            st = Timing.readTsc();
            for (int k = 0; k < count; k++) {
                long start = Timing.readTsc();
                tString(tStrg);
                durs[k] = Timing.readTsc() - start;
            }
            ds = Timing.tscToSecs(Timing.readTsc() - st);
            rate = count / ds;
            Log.print("AVG <String std> ds=%f rate=%f/s time/per=%f", ds, rate, 1.0 / rate);
            for (long dur : durs) {
                ds = Timing.tscToSecs(dur);
                Log.print("         ds=%f rate=%f/s time/per=%f", ds, 1.0 / ds, ds);
            }

            /*
             * Measure performance of parceling a String
             */
            System.gc();
            st = Timing.readTsc();
            for (int k = 0; k < count; k++) {
                long start = Timing.readTsc();
                tStringParcel(tStrg);
                durs[k] = Timing.readTsc() - start;
            }
            ds = Timing.tscToSecs(Timing.readTsc() - st);
            rate = count / ds;
            Log.print("AVG <String Parcel> ds=%f rate=%f/s time/per=%f", ds, rate, 1.0 / rate);
            for (long dur : durs) {
                ds = Timing.tscToSecs(dur);
                Log.print("         ds=%f rate=%f/s time/per=%f", ds, 1.0 / ds, ds);
            }

            /*
             * Measure performance of serializing a StringSer
             */
            System.gc();
            st = Timing.readTsc();
            for (int k = 0; k < count; k++) {
                long start = Timing.readTsc();
                tStringSer(tStrg);
                durs[k] = Timing.readTsc() - start;
            }
            ds = Timing.tscToSecs(Timing.readTsc() - st);
            rate = count / ds;
            Log.print("AVG <StringSer> ds=%f rate=%f/s time/per=%f", ds, rate, 1.0 / rate);
            for (long dur : durs) {
                ds = Timing.tscToSecs(dur);
                Log.print("         ds=%f rate=%f/s time/per=%f", ds, 1.0 / ds, ds);
            }

            /*
             * Measure performance of serializing a StringSer
             */
            System.gc();
            st = Timing.readTsc();
            StringSer tStrgSer = new StringSer(tStrg);
            for (int k = 0; k < count; k++) {
                long start = Timing.readTsc();
                tStringSer2(serdes, tStrgSer);
                durs[k] = Timing.readTsc() - start;
            }
            ds = Timing.tscToSecs(Timing.readTsc() - st);
            rate = count / ds;
            Log.print("AVG <StringSer> ds=%f rate=%f/s time/per=%f", ds, rate, 1.0 / rate);
            for (long dur : durs) {
                ds = Timing.tscToSecs(dur);
                Log.print("         ds=%f rate=%f/s time/per=%f", ds, 1.0 / ds, ds);
            }

            System.gc();
            Log.print("done test");
        } catch (Exception e) {
            Log.print("Exception e=%s", e);
            Log.printStackTrace(e);
        }
    }

    int tArray(byte data[]) throws Exception {
        ByteArrayOutputStream omb = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(omb);

        // Serialize
        oos.writeObject(data);
        oos.close();
        byte idata[] = omb.toByteArray();

        // Deserialize
        ByteArrayInputStream imb = new ByteArrayInputStream(idata);
        ObjectInputStream ois = new ObjectInputStream(imb);
        ois.readObject();

        return idata.length;
    }

    int tString(String str) throws Exception {
        ByteArrayOutputStream omb = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(omb);

        // Serialize
        oos.writeObject(str);
        oos.close();
        byte idata[] = omb.toByteArray();

        // Deserialize
        ByteArrayInputStream imb = new ByteArrayInputStream(idata);
        ObjectInputStream ois = new ObjectInputStream(imb);
        ois.readObject();

        return idata.length;
    }

    int tStringParcel(String str) throws Exception {
        Parcel parcel = Parcel.obtain();

        // Serialize
        parcel.writeString(str);
        byte b[] = parcel.marshall();

        // Deserialize
        parcel.unmarshall(b, 0, b.length);
        parcel.readString();

        return b.length;
    }

    int tStringSer(String str) throws Exception {
        SerdesBinary serdes = new SerdesBinary(str.length());

        // Serialize
        StringSer ss = new StringSer(str);
        ss.serialize(serdes);
        byte b[] = serdes.data();
        int len = serdes.size();

        // Deserialize
        serdes.init(b, 0, serdes.size());
        serdes.readObject();

        return len;
    }

    int tStringSer2(SerdesBinary serdes, StringSer str) throws Exception {
        // Serialize
        serdes.init();
        str.serialize(serdes);
        byte b[] = serdes.data();
        int len = serdes.size();

        // Deserialize
        serdes.init(b, 0, serdes.size());
        serdes.readObject();

        return len;
    }

}
